# = Class Vector
# Class that represents a mathematical vector
class Vector
  # Specific type of the vector contained in the instance. Possible values:
  # * vec_fil: Represents a row vector
  # * vec_row: Represents a column vector
  attr_reader :type
  attr_writer :type
  # Array containing the declared vector  
  attr_reader :value

  # Constructor of the class Vector
  # === Parameters
  # * value: Vector array containing the vector that wants to be created
  def initialize value
    @value = value
  end

  # Method that performs the operation self + vec
  # === Parameters:
  # * vec -> Element of type Vector that is to be added to self
  # === Return value:
  # Vector object containing the result of the operation
  def add vec
    if vec.size != size
      return "Los tamaños de los vectores no concuerdan " +
             "'#{vec.size[0]}x#{vec.size[1]}', '#{size[0]}x#{size[1]}'"
    end

    nval = @value
    for i in (0..@value.length-1)
      nval[i] += vec.value[i]
    end

    v = Vector.new nval
    v.type = @type
    v
  end

  # Method that performs the operation self - vec
  # === Parameters:
  # * obj -> Element of type Vector that is to be substracted from self
  # === Return value:
  # Vector object containing the result of the operation
  def minus vec
    if vec.size != size
      return "Los tamaños de los vectores no concuerdan " +
             "'#{vec.size[0]}x#{vec.size[1]}', '#{size[0]}x#{size[1]}'"
    end

    nval = @value
    for i in (0..@value.length-1)
      nval[i] -= vec.value[i]
    end

    v = Vector.new nval
    v.type = @type
    v
  end
  
  # Method that performs the operation - self
  # === Return value:
  # Vector object containing the result of the operation
  def uminus

    nval = []
    for i in (0..@value.length-1)
      nval[i] =  -@value[i]
    end

    v = Vector.new nval
    v.type = @type
    v
  end

  # Method that performs the operation self / int
  # === Parameters:
  # * int -> Element of type 'num' that is to be divided to self
  # === Return value:
  # Vector object containing the result of the operation
  def div int
    nval = []
    for n in @value
      nval.push(n / int)
    end
    v = Vector.new nval
    v.type = @type
    v
  end

  def prod int
    nval = []
    for n in @value
      nval.push(n * int)
    end
    v = Vector.new nval
    v.type = @type
    v
  end

  # Method that performs the scalar product (self, vec)
  # === Parameters:
  # * vec -> Element of type Vector that is to be multiplied to self
  # === Return value:
  # Float element containing the result of the operation
  def scalar_prod vec
    if vec.value.length != @value.length
      return "Los tamaños de los vectores no concuerdan " +
             "'#{vec.value.length }', '#{@value.length}'"
    end

    nval = 0
    for i in (0..@value.length-1)
      nval += vec.value[i] * @value[i]
    end

    nval
  end

  # Method that performs the vector product self x vec
  # === Parameters:
  # * vec -> Element of type Vector that is to be multiplied to self
  # === Return value:
  # Vector element containing the result of the operation
  def cross_prod vec
    if vec.value.length != 3 || @value.length != 3
      return "Los tamaños de los vectores no son 3 " +
             "'#{vec.value.length}', '#{@value.length}'"
    end

    v = Vector.new [
       @value[1] * vec.value[2] - @value[2] * vec.value[1],
       @value[2] * vec.value[0] - @value[0] * vec.value[2],
       @value[0] * vec.value[1] - @value[1] * vec.value[0],
    ]
    v.type = 'vec_fil'
    v
  end

  # Method that performs the operation to traspose self
  # === Return value:
  # Vector object containing the result of the operation
  def trasp
    v = Vector.new @value
    v.type = 'vec_col' == @type ? 'vec_fil' : 'vec_col'
    v
  end

  def assign range, val
    if range.kind_of?Fixnum
      value[range] = val
    else
      if 1 == val.value.length
        value[range[0]] = val.value[0]
      end
      if @type != val.type
        return "Asignando subvector de tipo distinto #{@val.type}"
      end
      if val.value.length < range[1] - range[0]
        t = range[1] - range[0]
        return "Asignando posición '#{t}' de vector de tamaño #{val.value.length}"
      end
      for i in (range[0]..range[1])
        value[i] = val.value[i - range[0]]
      end
    end
    nil
  end

  # Method that transforms self into a valid Matrix object
  # === Return value
  # Matrix object containing the equivalent matrix to the vector contained in self
  def matrix
    if 'vec_col' == @type
      nval = []
      for n in @value
        vec = Vector.new [n]
        vec.type = 'vec_fil'
        nval.push vec
      end
    else
      nval = [self]
    end
    Matrix.new nval
  end

  # Method that transforms the array into a printable string
  # === Return value
  # * String output -> String representation of the matrix
  def to_s
    max_pad = 0;
    for r in @value
      max_pad = r.to_s.length > max_pad ? r.to_s.length : max_pad 
    end
    ++ max_pad
    output = "\n|"
    for v in @value
      output += sprintf("%#{max_pad}.1f ", v)
      if 'vec_col' == @type
        output += "|\n|"
      end
    end
    if 'vec_col' == @type
      output = output[0, output.length - 1]
    else
      output += "|\n"
    end
    output
  end

  # Method that returns the dimensions of self
  # === Return value
  # Array containing the dimensions of self as follows:
  # * size[0] = number of rows
  # * size[1] = number of columns
  def size
    width = 'vec_fil' == @type ? @value.length : 1
    height = 'vec_fil' == @type ? 1 : @value.length
    return [height, width]
  end
end